/****************************************************************/
/*          S A S   S A M P L E   L I B R A R Y                 */
/*                                                              */
/*    NAME: TEMPLFT                                             */
/*   TITLE: PROC LIFETEST Template                              */
/* PRODUCT: STAT                                                */
/*  SYSTEM: ALL                                                 */
/*    KEYS: graphics, ods, survival analysis, Kaplan-Meier      */
/*   PROCS:                                                     */
/*    DATA:                                                     */
/*                                                              */
/* SUPPORT: saswfk                UPDATE: July 25, 2013         */
/*     REF: ods graphics                                        */
/*    MISC:                                                     */
/*   NOTES: This sample provides templates for the PROC         */
/*          LIFETEST survival plot that are modular and         */
/*          easier to modify than the default templates.        */
/****************************************************************/

%macro ProvideSurvivalMacros;

   %global atriskopts bandopts censored censorstr classopts
           graphopts groups insetopts legendopts ntitles stepopts tiplabel
           tips titletext0 titletext1 titletext2 xoptions yoptions;

   %let TitleText0 = METHOD " Survival Estimate";
   %let TitleText1 = &titletext0 " for " STRATUMID;
   %let TitleText2 = &titletext0 "s";         /* plural: Survival Estimates */
   %let nTitles    = 2;

   %let yOptions   = label="Survival Probability" shortlabel="Survival"
                     linearopts=(viewmin=0 viewmax=1
                                 tickvaluelist=(0 .2 .4 .6 .8 1.0));

   %let xOptions   = shortlabel=XNAME offsetmin=.05
                     linearopts=(viewmax=MAXTIME tickvaluelist=XTICKVALS
                                 tickvaluefitpolicy=XTICKVALFITPOL);

   %let Tips       = rolename=(_tip1= ATRISK _tip2=EVENT)
                     tiplabel=(_tip1="Number at Risk" _tip2="Observed Events")
                     tip=(x y _tip1 _tip2);
   %let TipLabel   = tiplabel=(y="Survival Probability");
   %let StepOpts   = ;

   %let Groups     = group=STRATUM index=STRATUMNUM;

   %let BandOpts   = &groups modelname="Survival";

   %let InsetOpts  = autoalign=(TOPRIGHT BOTTOMLEFT TOP BOTTOM)
                     border=true BackgroundColor=GraphWalls:Color Opaque=true;
   %let LegendOpts = title=GROUPNAME location=outside;

   %let AtRiskOpts = display=(label) valueattrs=(size=10pt);
   %let ClassOpts  = class=CLASSATRISK colorgroup=CLASSATRISK;

   %let Censored   = markerattrs=(symbol=plus);
   %let CensorStr  = "+ Censored";

   %let GraphOpts  = ;

   %macro StmtsBeginGraph; %mend;
   %macro StmtsTop;        %mend;
   %macro StmtsBottom;     %mend;

   %macro CompileSurvivalTemplates;
      %local outside;
      proc template;
         %do outside = 0 %to 1;
            define statgraph
               Stat.Lifetest.Graphics.ProductLimitSurvival%scan(2,2-&outside);
               dynamic NStrata xName plotAtRisk
                  %if %nrbquote(&censored) ne %then plotCensored;
                  plotCL plotHW plotEP labelCL labelHW labelEP maxTime xtickVals
                  xtickValFitPol rowWeights method StratumID classAtRisk 
                  plotTest GroupName Transparency SecondTitle TestName pValue
                  _byline_ _bytitle_ _byfootnote_;
               BeginGraph %if %nrbquote(&graphopts) ne %then / &graphopts;;

               if (NSTRATA=1)

                  %StmtsBeginGraph
                  %AtRiskLatticeStart
                  layout overlay / WALLDISPLAY=NONE xaxisopts=(&xoptions) yaxisopts=(&yoptions);
                     %StmtsTop
                     %SingleStratum
                     %StmtsBottom
                  endlayout;
                  %AtRiskLatticeEnd

               else
                  %StmtsBeginGraph
                  %AtRiskLatticeStart
                  layout overlay / WALLDISPLAY=NONE xaxisopts=(&xoptions) yaxisopts=(&yoptions);
                     %StmtsTop
                     %MultipleStrata
                     %StmtsBottom
                  endlayout;
                  %AtRiskLatticeEnd(class)

               endif;

               if (_BYTITLE_) entrytitle _BYLINE_ / textattrs=GRAPHVALUETEXT;
               else if (_BYFOOTNOTE_) entryfootnote halign=left _BYLINE_; endif;
               endif;
               EndGraph;
            end;
         %end;
      run;
   %mend;

   %macro pValue;
      if (PVALUE < .0001)
         entry TESTNAME " p " eval (PUT(PVALUE, PVALUE6.4));
      else
         entry TESTNAME " p=" eval (PUT(PVALUE, PVALUE6.4));
      endif;
   %mend;

   %macro SingleStratum;
      if (PLOTHW=1 AND PLOTEP=0)
         bandplot LimitUpper=HW_UCL LimitLower=HW_LCL x=TIME /
            modelname="Survival" fillattrs=GRAPHCONFIDENCE
            name="HW" legendlabel=LABELHW;
      endif;
      if (PLOTHW=0 AND PLOTEP=1)
         bandplot LimitUpper=EP_UCL LimitLower=EP_LCL x=TIME /
            modelname="Survival" fillattrs=GRAPHCONFIDENCE
            name="EP" legendlabel=LABELEP;
      endif;
      if (PLOTHW=1 AND PLOTEP=1)
         bandplot LimitUpper=HW_UCL LimitLower=HW_LCL x=TIME /
            modelname="Survival" fillattrs=GRAPHDATA1 datatransparency=.55
            name="HW" legendlabel=LABELHW;
         bandplot LimitUpper=EP_UCL LimitLower=EP_LCL x=TIME /
            modelname="Survival" fillattrs=GRAPHDATA2
            datatransparency=.55 name="EP" legendlabel=LABELEP;
      endif;
      if (PLOTCL=1)
         if (PLOTHW=1 OR PLOTEP=1)
            bandplot LimitUpper=SDF_UCL LimitLower=SDF_LCL x=TIME /
               modelname="Survival" display=(outline)
               outlineattrs=GRAPHPREDICTIONLIMITS name="CL" legendlabel=LABELCL;
         else
            bandplot LimitUpper=SDF_UCL LimitLower=SDF_LCL x=TIME /
               modelname="Survival" fillattrs=GRAPHCONFIDENCE name="CL"
               legendlabel=LABELCL;
         endif;
      endif;

      stepplot y=SURVIVAL x=TIME / name="Survival" &tips legendlabel="Survival"
               &stepopts;

      if (PLOTCENSORED=1)
         scatterplot y=CENSORED x=TIME / &censored &tiplabel
            name="Censored" legendlabel="Censored";
      endif;

      if (PLOTCL=1 OR PLOTHW=1 OR PLOTEP=1)
         discretelegend "Censored" "CL" "HW" "EP" / location=outside
            halign=center;
      else
         if (PLOTCENSORED=1)
            discretelegend "Censored" / location=inside
                                        autoalign=(topright bottomleft);
         endif;
      endif;
      %if not &outside %then %do;
         if (PLOTATRISK=1)
            innermargin / align=bottom;
               axistable x=TATRISK value=ATRISK / &atriskopts;
            endinnermargin;
         endif;
      %end;
   %mend;

   %macro MultipleStrata;
     if (PLOTHW=1)
         bandplot LimitUpper=HW_UCL LimitLower=HW_LCL x=TIME / &bandopts
                  datatransparency=Transparency;
      endif;
      if (PLOTEP=1)
         bandplot LimitUpper=EP_UCL LimitLower=EP_LCL x=TIME / &bandopts
                  datatransparency=Transparency;
      endif;
      if (PLOTCL=1)
         if (PLOTHW=1 OR PLOTEP=1)
            bandplot LimitUpper=SDF_UCL LimitLower=SDF_LCL x=TIME / &bandopts
                     display=(outline) outlineattrs=(pattern=ShortDash);
         else
            bandplot LimitUpper=SDF_UCL LimitLower=SDF_LCL x=TIME / &bandopts
                     datatransparency=Transparency;
         endif;
      endif;

      stepplot y=SURVIVAL x=TIME / &groups name="Survival" &tips &stepopts;

      if (PLOTCENSORED=1)
         scatterplot y=CENSORED x=TIME / &groups &tiplabel &censored;
      endif;

      %if not &outside %then %do;
         if (PLOTATRISK=1)
            innermargin / align=bottom;
               axistable x=TATRISK value=ATRISK / &atriskopts &classopts;
            endinnermargin;
         endif;
      %end;

      %if %nrbquote(&legendopts) ne %then %do;
         DiscreteLegend "Survival" / &legendopts;
      %end;

      %if %nrbquote(&insetopts) ne %then %do;
         if (PLOTCENSORED=1)
            if (PLOTTEST=1)
               layout gridded / rows=2 &insetopts;
                  entry &censorstr;
                  %pValue
               endlayout;
            else
               layout gridded / rows=1 &insetopts;
                  entry &censorstr;
               endlayout;
            endif;
         else
            if (PLOTTEST=1)
               layout gridded / rows=1 &insetopts;
                  %pValue
               endlayout;
            endif;
         endif;
         %end;

   %mend;

   %macro SurvTabHeader(multiple);
      %if &multiple %then %do; entry ""; %end;
      entry "";
      entry "";
      entry "";
      entry &r "Median";
      entry "";
      entry "";

      %if &multiple %then %do; entry ""; %end;
      entry &r "Subjects";
      entry &r "Event";
      entry &r "Censored";
      entry &r "Survival";
      entry &r PctMedianConfid;
      entry halign=left  "CL";
   %mend;

   %macro SurvivalTable;
      %local fmt r i t;
      %let fmt = bestd6.;
      %let r = halign = right;
      columnheaders;
         layout overlay / pad=(top=5);
            if(NSTRATA=1)
               layout gridded / columns=6 border=TRUE;
                  dynamic PctMedianConfid NObs NEvent Median
                          LowerMedian UpperMedian;
                  %SurvTabHeader(0)
                  entry &r NObs;
                  entry &r NEvent;
                  entry &r eval(NObs-NEvent);
                  entry &r eval(put(Median,&fmt));
                  entry &r eval(put(LowerMedian,&fmt));
                  entry &r eval(put(UpperMedian,&fmt));
               endlayout;
            else
               layout gridded / columns=7 border=TRUE;
                  dynamic PctMedianConfid;
                  %SurvTabHeader(1)
                  %do i = 1 %to 10;
                     %let t = / textattrs=GraphData&i;
                     dynamic StrVal&i NObs&i NEvent&i Median&i
                             LowerMedian&i UpperMedian&i;
                     if (&i <= nstrata)
                        entry &r StrVal&i &t;
                        entry &r NObs&i &t;
                        entry &r NEvent&i &t;
                        entry &r eval(NObs&i-NEvent&i) &t;
                        entry &r eval(put(Median&i,&fmt)) &t;
                        entry &r eval(put(LowerMedian&i,&fmt)) &t;
                        entry &r eval(put(UpperMedian&i,&fmt)) &t;
                     endif;
                  %end;
               endlayout;
            endif;
         endlayout;
      endcolumnheaders;
   %mend;

   %macro SurvivalSummaryTable;
      %macro AtRiskLatticeStart;
         layout lattice / columndatarange=union rowgutter=10
            rows=%if &outside %then 2 rowweights=ROWWEIGHTS;
                 %else              1;;
         %if &outside %then %do; cell; %end;
      %mend;

      %macro AtRiskLatticeEnd(useclassopts);
         %if &outside %then %do;
            endcell;
            cell;
               layout overlay / walldisplay=none xaxisopts=(display=none);
                  axistable x=TATRISK value=ATRISK / &atriskopts
                            %if &useclassopts ne %then &classopts;;
               endlayout;
            endcell;
         %end;
         %SurvivalTable
         endlayout;
      %mend;
   %mend;

   %macro AtRiskLatticeStart;
      %if &outside %then %do;
         layout lattice / rows=2 rowweights=ROWWEIGHTS
                          columndatarange=union rowgutter=10;
         cell;
      %end;
   %mend;

   %macro AtRiskLatticeEnd(useclassopts);
      %if &outside %then %do;
         endcell;
         cell;
            layout overlay / walldisplay=none xaxisopts=(display=none);
               axistable x=TATRISK value=ATRISK / &atriskopts
                         %if &useclassopts ne %then &classopts;;
            endlayout;
         endcell;
      endlayout;
      %end;
   %mend;

%CompileSurvivalTemplates
%mend;
